package com.zyk.scaffold.common.utils;

import org.apache.commons.codec.binary.Base64;
import sun.security.rsa.RSAPrivateCrtKeyImpl;
import sun.security.rsa.RSAPublicKeyImpl;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.List;
import java.util.Random;

public class RSAUtil {

	public static String encrypt(String context, String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
		return encrypt(new BigInteger(context), publicKey).toString();
	}

	public static BigInteger encrypt(BigInteger context, String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
		// 对密钥解密
		byte[] keyBytes = Base64.decodeBase64(publicKey);
		// 取得私钥
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		RSAPublicKeyImpl rsaPublicKey = (RSAPublicKeyImpl) keyFactory.generatePublic(x509KeySpec);
		BigInteger n = rsaPublicKey.getModulus();
		BigInteger e = rsaPublicKey.getPublicExponent();
		BigInteger M = context;
		return encrypt(M, n, e);
	}

	/**
	 * 加密
	 * <p> C=M^e(mod n)
	 * @param M
	 * @param n
	 * @param e
	 * @return
	 */
	public static BigInteger encrypt(BigInteger M, BigInteger n, BigInteger e) {
		return M.modPow(e, n);
	}

	public static String decrypt(String context, String privateKey) throws InvalidKeySpecException, NoSuchAlgorithmException {
		return decrypt(new BigInteger(context), privateKey).toString();
	}

	public static BigInteger decrypt(BigInteger context, String privateKey) throws InvalidKeySpecException, NoSuchAlgorithmException {
		// 对密钥解密
		byte[] keyBytes = Base64.decodeBase64(privateKey);
		// 取得私钥
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		RSAPrivateCrtKeyImpl rsaPrivateKey = (RSAPrivateCrtKeyImpl) keyFactory.generatePrivate(pkcs8KeySpec);
		BigInteger C = context;
		BigInteger n = rsaPrivateKey.getModulus();
		BigInteger d = rsaPrivateKey.getPrivateExponent();
		return decrypt(C, n, d);
	}

	/**
	 * 解密
	 * <p> M=C^d(mod n)
	 * @param C
	 * @param n
	 * @param d
	 * @return
	 */
	public static BigInteger decrypt(BigInteger C, BigInteger n, BigInteger d) {
		return C.modPow(d, n);
	}


	public static void main(String[] args) throws Exception {
		String publicS = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCG1iToVro1RFxvrlRSBwNr/hzc9fTwKafObSElu8Tv5ICNb76htldEVgosCtdSuQXpsTEivsM81rNJIt7w943T8tm10pMvNjEKABUqD4RhGNsofyFUYFzwrMnAcKybP2X42tEzMzaWcXifpT62thxuW/UIsvwNXKtP40Pk1t3OmQIDAQAB";
		String privateS = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIbWJOhWujVEXG+uVFIHA2v+HNz19PApp85tISW7xO/kgI1vvqG2V0RWCiwK11K5BemxMSK+wzzWs0ki3vD3jdPy2bXSky82MQoAFSoPhGEY2yh/IVRgXPCsycBwrJs/Zfja0TMzNpZxeJ+lPra2HG5b9Qiy/A1cq0/jQ+TW3c6ZAgMBAAECgYBr+Ii/X8tmIiKe74rn0GPmEysLqQyFT+Xmv65eZ9iQfHqQR13wYnHI79jfYaMAw9Y/Rrtg5j6ytf4E356EeMchOtqXMCseykYFDXyi9Je67gebnxPj/1UthK43jfJlO+V1RF8XDWN5tDUk6Rs9v5TMFkZ4uLBUqDEmLk/mPQTjMQJBAL7itXxgO+r6yvOgaawS6duUmQHAA23F9WdTQZZiZckbVLl0H8+51CCXzRHoM46AF5MGOxdNsOeaXR8GSWeDuI0CQQC01ONlWBo9LGzMW9nwZM8wRJOpgByOJyGfvTK6fpCnExGMQa2TGG4K7mhZEBtYB0n7+tepRDdLBb8L13TJLWk9AkEAtx4ZaEWRdWw9wdWDShWizokQ90LShz4+m26dHr0qU/CqKHakBcyJGPNHQQR2YR+0fdCeY06ehK/q4VZQmMMeCQJAVBALTddxCzMVuMKSQ+B5OJUIl+lIXQTv6pRHes7Pa/u/UpZNnG3k6gv+UjjcnUV2LT9k9fkSQzv+ngCg98y2eQJATW2n2p+RMbjHlJFXl3UhJ4huQVFwYlQShFWrbP0BKJ3uAl1ICvZ1VWMWPa177vRmIng7RkA7iwpCS3yDHqrE1A==";
		// 1024长度的BigInteger
		String data = new BigInteger(1024, new Random()).toString();
		// Long 数据 -> BigInteger
		// String data = BigInteger.valueOf(Math.abs(new Random().nextLong())).toString();
		System.out.println(data);
		System.out.println("========================================");
		// 公钥加密
		String encrypt = RSAUtil.encrypt(data, publicS);
		System.out.println("========================================");
		String decrypt = RSAUtil.decrypt(encrypt, privateS);
		System.out.println(decrypt);
		System.out.println("========================================");
		System.out.println(data);
	}
}